#include "ThirdPersonController.h"
#include "Animation.h"
#include "TPCidle.h"
#include "TPCwalking.h"
#include "Logger.h"
#include "Exception.h"

using namespace game_engine;
using namespace game_engine::components;
using namespace game_engine::library;
using namespace game_engine::utils;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

ThirdPersonController::ThirdPersonController(void)
    : Behaviour(), idleAnimationId(), walkSpeed(0.0f), runSpeed(0.0f),
    canJump(false), idleState(NULL), walkingState(NULL), prevDirection(IDLE),
    directionUpdated(false)
{
    type = "ThirdPersonController";
    walkAnimationId.clear();
    runAnimationId.clear();
    jumpAnimationId.clear();
}

ThirdPersonController::ThirdPersonController(GameObject *obj)
    : Behaviour(obj), idleAnimationId(), walkSpeed(0.0f), runSpeed(0.0f),
    canJump(false), idleState(NULL), walkingState(NULL), prevDirection(IDLE),
    directionUpdated(false)
{
    type = "ThirdPersonController";
    walkAnimationId.clear();
    runAnimationId.clear();
    jumpAnimationId.clear();
}

ThirdPersonController::~ThirdPersonController(void)
{
    delete idleState;
    delete walkingState;
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

void ThirdPersonController::initialize(void) throw(...)
{
    // Create states for this behaviour
    idleState = new TPCidle(this);
    walkingState = new TPCwalking(this);
    setCurrentState(idleState);

    // Check that all not NULL animations are defined into an
    // Animation component of the same object
    Animation *anim = dynamic_cast<Animation*> (getComponent(object, "Animation"));
    vector<string> list;
    list.push_back(idleAnimationId);

    map<Direction,string>::const_iterator j;
    for (j=walkAnimationId.begin(); j!=walkAnimationId.end(); j++)
    {
        list.push_back((*j).second);
    }
    
    //list.push_back(runAnimationId);
    //list.push_back(jumpAnimationId);
    vector<string>::iterator it;
    for (it=list.begin(); it<list.end(); it++)
    {
        if ((!(*it).empty()) && (!anim->sequenceExists(*it)))
        {
            string err("Animation ");
            err.append(*it);
            err.append(" not defined in Animation component");
            Logger::ERR(GAMEENGINE_LOG, err);
            throw NoSuchElementException(err);
        }
    }

    // Base class initialization
    Behaviour::initialize();
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

const string& ThirdPersonController::getIdleAnimationId(void) const
{
    return idleAnimationId;
}

const string ThirdPersonController::getWalkAnimationId(const Direction direction) const
{
    // Check for existance
    map<Direction,string>::const_iterator it;
    it = walkAnimationId.find(direction);
    if (it == walkAnimationId.end())
    {
        return string();
    }
    return (*it).second;
}

const FLOAT32 ThirdPersonController::getWalkSpeed(void) const
{
    return walkSpeed;
}

const Direction ThirdPersonController::getPrevDirection(void)
{
    directionUpdated = false;
    return prevDirection;
}

const BOOL ThirdPersonController::getDirectionUpdated(void) const
{
    return directionUpdated;
}

///////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////

void ThirdPersonController::setIdleAnimationId(const string &animId)
{
    idleAnimationId = animId;
}

void ThirdPersonController::setWalkAnimationId(const Direction direction, 
                                               const string &animId)
{
    walkAnimationId[direction] = animId;
}

//void ThirdPersonController::setRunAnimationId(const string &animId)
//{
//    runAnimationId = animId;
//}
//
//void ThirdPersonController::setJumpAnimationId(const string &animId)
//{
//    jumpAnimationId = animId;
//}

void ThirdPersonController::setWalkSpeed(const FLOAT32 speed)
{
    walkSpeed = speed;
}

void ThirdPersonController::setRunSpeed(const FLOAT32 speed)
{
    runSpeed = speed;
}

void ThirdPersonController::setCanJump(const BOOL flag)
{
    canJump = flag;
}

void ThirdPersonController::setPrevDirection(const Direction dir)
{
    if (dir != prevDirection)
    {
        prevDirection = dir;
        directionUpdated = true;
    }
    else
    {
        directionUpdated = false;
    }
}
